﻿using System;
using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//using System.Windows.Forms; 
//using System.Reflection;
using HarmonyLib;
using TaleWorlds.Core;
using TaleWorlds.MountAndBlade;
using Helpers; // TaleWorlds.MountAndBlade.Helpers.dll
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.SandBox.GameComponents;
using TaleWorlds.Localization;

/* references
 * TaleWorlds.Library.dll
 * TaleWorlds.CampaignSystem.dll
 * TaleWorlds.MountAndBlade.dll
 * TaleWorlds.MountAndBlade.Helpers.dll
 * TaleWorlds.Localization.dll
 * TaleWorlds.Core.dll
 * 0Harmony.dll
*/


// TaleWorlds.CampaignSystem.SandBox.GameComponents.DefaultSettlementFoodModel
// TaleWorlds.CampaignSystem.SandBox.GameComponents.DefaultSettlementGarrisonModel


// Garrisons don't eat food | either edit CalculateTownFoodChangeInternal (CTD) or dupe the garrison effect +-=0 at CalculateTownFoodStocksChange
// Garrisons don't starve

namespace VsMod_GarrisonsDontEatNorStarve
{
	public class VsMod_GarrisonsDontEatNorStarve_SubModule : MBSubModuleBase
	{
		protected override void OnSubModuleLoad()
		{
			base.OnSubModuleLoad();
			var harmony = new Harmony("asdasdadsadsasdasdasdasdadsadsa");
			harmony.PatchAll();
		}
		protected override void OnBeforeInitialModuleScreenSetAsRoot()
		{
			base.OnBeforeInitialModuleScreenSetAsRoot();
			InformationManager.DisplayMessage(new InformationMessage("Vaeringjar's Garrisons Don't Eat Nor Starve [v2.0]"));
		}

		// for reflection? // based on bannerlord tweaks
		protected override void OnGameStart(Game game, IGameStarter gameStarterObject)
		{
			base.OnGameStart(game, gameStarterObject);

			AddModels(gameStarterObject as CampaignGameStarter);
		}
		private void AddModels(CampaignGameStarter gameStarter)
		{
			if (gameStarter != null)
			{
				gameStarter.AddModel(new DefaultSettlementGarrisonModel());
			}
		}
	}


	// -------------------------------------------------------------------------------- # DefaultSettlementFoodModel # 

	// CalculateTownFoodChangeInternal // CalculateTownFoodStocksChange
	//[HarmonyPatch(typeof(DefaultSettlementFoodModel))] //[HarmonyPatch("CalculateTownFoodChangeInternal", new Type[] { typeof(Town), typeof(StatExplainer) })]
	[HarmonyPatch(typeof(DefaultSettlementFoodModel), "CalculateTownFoodStocksChange")]
	internal class VzMod_TESTS_Override1
	{
		public static void Postfix(Town town, StatExplainer explanation, ref float __result)
		{
			if (!town.IsUnderSiege)
			{
				TextObject _thisisatextobject = new TextObject("Garrison Logistics");
				ExplainedNumber explainedNumber = new ExplainedNumber(0f, explanation, null);

				MobileParty garrisonParty = town.GarrisonParty;
				int num = (garrisonParty != null) ? garrisonParty.Party.NumberOfAllMembers : 0;
				num = num / 20;
				explainedNumber.Add((float)num, _thisisatextobject);

				__result += (int)explainedNumber.ResultNumber;
			}
		}
	}

	// -------------------------------------------------------------------------------- # DefaultSettlementGarrisonModel # 
	// DefaultSettlementGarrisonModel is inaccessible due to its protection level // need to use "reflection"

	// for e1.0.6

	// thanks "Doombox" 

	// copypasta from dnSpy

	// Token: 0x020001F6 RID: 502
	internal class DefaultSettlementGarrisonModel : SettlementGarrisonModel
	{
		// Token: 0x06001EBB RID: 7867 RVA: 0x00077F8C File Offset: 0x0007618C
		public override int CalculateGarrisonChange(Settlement settlement, StatExplainer explanation = null)
		{
			return DefaultSettlementGarrisonModel.CalculateGarrisonChangeInternal(settlement, explanation);
		}

		// Token: 0x06001EBC RID: 7868 RVA: 0x00077F98 File Offset: 0x00076198
		private static int CalculateGarrisonChangeInternal(Settlement settlement, StatExplainer explanation = null)
		{
			ExplainedNumber explainedNumber = new ExplainedNumber(0f, explanation, null);
			if (settlement.IsTown || settlement.IsCastle)
			{
				float loyalty = settlement.Town.Loyalty;
				if (settlement.IsStarving && settlement.IsUnderSiege)																							// <- <- <- <- <- <- <- <- <-
				{
					float foodChange = settlement.Town.FoodChange;
					int num = (settlement.Town.Owner.IsStarving && foodChange < 0f) ? ((int)(foodChange / 8f)) : 0;
					explainedNumber.Add((float)num, DefaultSettlementGarrisonModel._foodShortageText);
				}
				if (settlement.Town.GarrisonParty != null && ((float)settlement.Town.GarrisonParty.Party.NumberOfHealthyMembers + explainedNumber.ResultNumber) / (float)settlement.Town.GarrisonParty.Party.PartySizeLimit > settlement.Town.GarrisonParty.PaymentRatio)
				{
					int num2 = 0;
					do
					{
						num2++;
					}
					while (((float)settlement.Town.GarrisonParty.Party.NumberOfHealthyMembers + explainedNumber.ResultNumber - (float)num2) / (float)settlement.Town.GarrisonParty.Party.PartySizeLimit >= settlement.Town.GarrisonParty.PaymentRatio && (float)settlement.Town.GarrisonParty.Party.NumberOfHealthyMembers + explainedNumber.ResultNumber - (float)num2 > 0f && num2 < 20);
					explainedNumber.Add((float)(-(float)num2), DefaultSettlementGarrisonModel._paymentIsLess);
				}
			}
			DefaultSettlementGarrisonModel.GetSettlementGarrisonChangeDueToIssues(settlement, ref explainedNumber);
			return (int)explainedNumber.ResultNumber;
		}

		// Token: 0x06001EBD RID: 7869 RVA: 0x00078110 File Offset: 0x00076310
		private static void GetSettlementGarrisonChangeDueToIssues(Settlement settlement, ref ExplainedNumber result)
		{
			float value;
			if (IssueManager.DoesSettlementHasIssueEffect(DefaultIssueEffects.SettlementGarrison, settlement, out value))
			{
				result.Add(value, DefaultSettlementGarrisonModel._issues);
			}
		}

		// Token: 0x06001EBE RID: 7870 RVA: 0x00078138 File Offset: 0x00076338
		public override int FindNumberOfTroopsToTakeFromGarrison(MobileParty mobileParty, Settlement settlement)
		{
			MobileParty garrisonParty = settlement.Town.GarrisonParty;
			if (garrisonParty != null)
			{
				float totalStrength = garrisonParty.Party.TotalStrength;
				float num = FactionHelper.FindIdealGarrisonStrengthPerWalledCenter(mobileParty.MapFaction as Kingdom, settlement.OwnerClan);
				float num2 = FactionHelper.OwnerClanEconomyEffectOnGarrisonSizeConstant(settlement.OwnerClan);
				num *= num2;
				num *= (settlement.IsTown ? 2f : 1f);
				float num3 = (float)mobileParty.Party.PartySizeLimit * mobileParty.PaymentRatio;
				int numberOfAllMembers = mobileParty.Party.NumberOfAllMembers;
				float num4 = Math.Min(12f, num3 / (float)numberOfAllMembers) - 1f;
				float num5 = (float)Math.Pow((double)(totalStrength / num), 1.5);
				float num6 = (mobileParty.LeaderHero.Clan.Leader == mobileParty.LeaderHero) ? 2f : 1f;
				int num7 = MBRandom.RoundRandomized(num4 * num5 * num6);
				int num8 = 20;
				num8 *= (settlement.IsTown ? 2 : 1);
				if (num7 > garrisonParty.Party.MemberRoster.TotalRegulars - num8)
				{
					num7 = garrisonParty.Party.MemberRoster.TotalRegulars - num8;
				}
				return num7;
			}
			return 0;
		}

		// Token: 0x06001EBF RID: 7871 RVA: 0x0007826C File Offset: 0x0007646C
		public override int FindNumberOfTroopsToLeaveToGarrison(MobileParty mobileParty, Settlement settlement)
		{
			MobileParty garrisonParty = settlement.Town.GarrisonParty;
			float num = 0f;
			if (garrisonParty != null)
			{
				num = garrisonParty.Party.TotalStrength;
			}
			float num2 = FactionHelper.FindIdealGarrisonStrengthPerWalledCenter(mobileParty.MapFaction as Kingdom, settlement.OwnerClan);
			float num3 = FactionHelper.OwnerClanEconomyEffectOnGarrisonSizeConstant(settlement.OwnerClan);
			num2 *= num3;
			num2 *= (settlement.IsTown ? 2f : 1f);
			if ((settlement.OwnerClan.Leader != Hero.MainHero || (mobileParty.LeaderHero != null && mobileParty.LeaderHero.Clan == Clan.PlayerClan)) && num < num2)
			{
				int numberOfRegularMembers = mobileParty.Party.NumberOfRegularMembers;
				float num4 = 1f + (float)mobileParty.Party.NumberOfWoundedRegularMembers / (float)mobileParty.Party.NumberOfRegularMembers;
				float num5 = (float)mobileParty.Party.PartySizeLimit * mobileParty.PaymentRatio;
				float num6 = (float)(Math.Pow((double)Math.Min(2f, (float)numberOfRegularMembers / num5), 1.2000000476837158) * 0.75);
				float num7 = (1f - num / num2) * (1f - num / num2);
				if (mobileParty.Army != null)
				{
					num7 = Math.Min(num7, 0.5f);
				}
				float num8 = 0.5f;
				if (settlement.OwnerClan == mobileParty.Leader.HeroObject.Clan || settlement.OwnerClan == mobileParty.Party.Owner.MapFaction.Leader.Clan)
				{
					num8 = 1f;
				}
				float num9 = (mobileParty.Army != null) ? 1.25f : 1f;
				float num10 = 1f;
				List<float> list = new List<float>(5);
				for (int i = 0; i < 5; i++)
				{
					list.Add(Campaign.MapDiagonal * Campaign.MapDiagonal);
				}
				foreach (Kingdom kingdom in Kingdom.All)
				{
					if (kingdom.IsKingdomFaction && mobileParty.MapFaction.IsAtWarWith(kingdom))
					{
						foreach (Settlement settlement2 in kingdom.Settlements)
						{
							float num11 = settlement2.Position2D.DistanceSquared(mobileParty.Position2D);
							for (int j = 0; j < 5; j++)
							{
								if (num11 < list[j])
								{
									for (int k = 4; k >= j + 1; k--)
									{
										list[k] = list[k - 1];
									}
									list[j] = num11;
									break;
								}
							}
						}
					}
				}
				float num12 = 0f;
				for (int l = 0; l < 5; l++)
				{
					num12 += (float)Math.Sqrt((double)list[l]);
				}
				num12 /= 5f;
				float num13 = Math.Max(0f, Math.Min(Campaign.MapDiagonal / 15f - Campaign.MapDiagonal / 30f, num12 - Campaign.MapDiagonal / 30f));
				float num14 = Campaign.MapDiagonal / 15f - Campaign.MapDiagonal / 30f;
				float num15 = num13 / num14;
				float num16 = Math.Min(0.7f, num10 * num6 * num7 * num8 * num9 * num4);
				return MBRandom.RoundRandomized((float)numberOfRegularMembers * num16);
			}
			return 0;
		}

		// Token: 0x04000C29 RID: 3113
		private static readonly TextObject _townWallsText = new TextObject("{=SlmhqqH8}Town Walls", null);

		// Token: 0x04000C2A RID: 3114
		private static readonly TextObject _moraleText = new TextObject("{=UjL7jVYF}Morale", null);

		// Token: 0x04000C2B RID: 3115
		private static readonly TextObject _foodShortageText = new TextObject("{=qTFKvGSg}Food Shortage", null);

		// Token: 0x04000C2C RID: 3116
		private static readonly TextObject _surplusFoodText = GameTexts.FindText("str_surplus_food", null);

		// Token: 0x04000C2D RID: 3117
		private static readonly TextObject _recruitFromCenterNotablesText = GameTexts.FindText("str_center_notables", null);

		// Token: 0x04000C2E RID: 3118
		private static readonly TextObject _recruitFromVillageNotablesText = GameTexts.FindText("str_village_notables", null);

		// Token: 0x04000C2F RID: 3119
		private static readonly TextObject _villageBeingRaided = GameTexts.FindText("str_village_being_raided", null);

		// Token: 0x04000C30 RID: 3120
		private static readonly TextObject _villageLooted = GameTexts.FindText("str_village_looted", null);

		// Token: 0x04000C31 RID: 3121
		private static readonly TextObject _townIsUnderSiege = GameTexts.FindText("str_villages_under_siege", null);

		// Token: 0x04000C32 RID: 3122
		private static readonly TextObject _retiredText = GameTexts.FindText("str_retired", null);

		// Token: 0x04000C33 RID: 3123
		private static readonly TextObject _paymentIsLess = GameTexts.FindText("str_payment_is_less", null);

		// Token: 0x04000C34 RID: 3124
		private static readonly TextObject _issues = new TextObject("{=D7KllIPI}Issues", null);
	}

	// --------------------------------------------------------------------------------

}
